﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace YDT.Payment.Application
{
    public class HttpHandler : DelegatingHandler
    {
        private readonly string merchantId;
        private readonly string serialNo;

        public HttpHandler(string merchantId, string merchantSerialNo)
        {
            InnerHandler = new HttpClientHandler();

            this.merchantId = merchantId;
            this.serialNo = merchantSerialNo;
        }

        protected async override Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            var auth = await BuildAuthAsync(request);
            string value = $"WECHATPAY2-SHA256-RSA2048 {auth}";
            request.Headers.Add("Authorization", value);

            return await base.SendAsync(request, cancellationToken);
        }
        
        /// <summary>
        /// 创建Authorization
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>

        protected async Task<string> BuildAuthAsync(HttpRequestMessage request)
        {
            string method = request.Method.ToString();
            string body = "";
            if (method == "POST" || method == "PUT" || method == "PATCH")
            {
                var content = request.Content;
                body = await content.ReadAsStringAsync();
            }

            string uri = request.RequestUri.PathAndQuery;
            var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
            string nonce = Path.GetRandomFileName();

            string message = $"{method}\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
           // string signature = Sign(message);
            var path = "apiclient_cert.p12";
            string signature = Sign(message, path, merchantId);
            return $"mchid=\"{merchantId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{serialNo}\",signature=\"{signature}\"";
        }

        /// <summary>
        //// <summary>
        /// 根据证书签名数据
        /// </summary>
        /// <param name="data">要签名的数据</param>
        /// <param name="certPah">证书路径</param>
        /// <param name="certPwd">密码</param>
        /// <returns></returns>
        public string Sign(string data, string certPah, string certPwd)
        {
            // 1、需要私钥
            var rsa = GetPrivateKey(certPah, certPwd);

            var rsaClear = new RSACryptoServiceProvider();

            var paras = rsa.ExportParameters(true);
            rsaClear.ImportParameters(paras);

            var signData = rsa.SignData(Encoding.UTF8.GetBytes(data), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
            // 2、base64
            return Convert.ToBase64String(signData);
        }


        /// <summary>
        /// 根据证书获取私钥
        /// </summary>
        /// <param name="priKeyFile">证书文件路径</param>
        /// <param name="keyPwd">密码</param>
        /// <returns></returns>
        private static RSA GetPrivateKey(string priKeyFile, string keyPwd)
        {
            X509Certificate2 cer = new X509Certificate2(priKeyFile, keyPwd, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
            //var pc = new X509Certificate2(priKeyFile, keyPwd, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
            if (cer.HasPrivateKey)
            {
                Console.WriteLine("私钥不存在");
            }
            return (RSA)cer.PrivateKey;
        }
    }
}
